/*
 * Copyright (c) 2011, 2012 Alexander Kluth <alexander.kluth@outlook.com>
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package hardyhttp.server.handler;

import hardyhttp.filesystem.Logger;
import java.io.*;
import java.net.*;
import com.sun.net.httpserver.*;

import hardyhttp.filesystem.Filesystem;
import hardyhttp.server.*;
import hardyhttp.server.helper.*;

/**
 *
 * @author akluth
 */
public class CommonHandler 
{
    Filesystem fs;
    Logger logger;
    HttpStatusCodes httpcodes = new HttpStatusCodes();
    HTMLTemplates templates = new HTMLTemplates();
    Headers header; 
    OutputStream os = null;
    byte[] res = null; 
    String phppath;
    String htdocs;
    
    
    public CommonHandler(Logger logger, String htdocs, String phppath)
    {
        this.logger = logger;
        this.phppath = phppath;
        fs = new Filesystem(htdocs);
        this.htdocs = htdocs;
    }
    
    
    // Our "common" handler for handling "common" events - 
    // this means a simple request for a file
    public HttpHandler commonHandler = new HttpHandler()
    {
        @Override
        public void handle(HttpExchange exchange)
        {             
            header = exchange.getResponseHeaders();
            httpcodes.setHttpExchange(exchange);
            httpcodes.setLogger(logger);
            
            // Get the requested URL and build the complete
            // filesystem-string related to the current directory
            String uri = exchange.getRequestURI().toString();
            String reqfile = fs.getFile(uri);
             
            // Check if file exist
            if (!fs.fileExist(reqfile))
            {                
                logger.logEvent("[HTTPD]  WARNING: Requested file " + reqfile + " not available.");
                
                if (httpcodes.send404() == false)
                {
                    logger.logEvent("[HTTPD]  CRITICAL: Terminating.");
                    System.exit(-1);
                }
            }

            // Check, if the requested file is a directory
            if (fs.isDir(reqfile))
            {
                String tmp;
                
                // If index-file not found, print out the contents of the directory
                if ((tmp = fs.searchForIndexFile(reqfile)) == null)
                {
                    String str = "";
                    String[] files;
                    
                    str += templates.insertHTMLHeading("Contents of " + uri);
                    
                    String[] myfiles = fs.getDirectoryContent(reqfile);
                    
                    // When we are in the root directory do not add a / after the path
                    if (uri.equals("/"))
                        files = fs.getDirectoryContentRelative(myfiles, "."+uri, true);
                    
                    else
                        files = fs.getDirectoryContentRelative(myfiles, "."+uri, false);

                    str += templates.insertDirectoryContent(uri, htdocs, files, myfiles);
                    str += templates.insertHTMLFooter() + "\n";
                    
                    res = str.getBytes();
                    header.add("Content-type", "text/html");
                }
                
                // index.html or index.htm found, reading file in
                else
                {
                    reqfile += "/" + tmp;
                    
                    res = new byte[(int)fs.fileLength(reqfile)];
                    res = fs.readFile(reqfile);

                    header.add("Content-type", "text/html");
                }
            }
            
            // File is not a directory, reading in
            else
            {
                res = new byte[(int)fs.fileLength(reqfile)];
                res = fs.readFile(reqfile);
                
                header.add("Content-type", contentType(reqfile));
            }   
            
            logger.logEvent("[HTTPD]  Client " + exchange.getRemoteAddress().toString() + " connected.");
                
            if (fs.isDir(reqfile))
                logger.logEvent("[HTTPD]  Sending contents of directory " + reqfile);
                
            else
                logger.logEvent("[HTTPD]  Sending file " + reqfile);
                
            // Send everything to the client
            try
            {
                httpcodes.send200(res.length);                   
                os = exchange.getResponseBody();                 
                os.write(res, 0, res.length);
                logger.logEvent("[HTTPD]  File " + reqfile + " completly sent.");
            }
            
            // If this happened, something is fucked up - IOException is quite
            // generic, so I think we should add more granularity here...
            //FIXME: More granularity?
            catch (IOException ioe)
            {
                logger.logEvent("[HTTPD]  ERROR: Could not send the requested file " + reqfile + " to " + exchange.getRemoteAddress().toString());
                    
                if (httpcodes.send500() == false)
                {
                    logger.logEvent("[HTTPD]  CRITICAL: Terminating.");
                    System.exit(-1);
                }
            }
                
            // Okay, what if we could not close the output stream?
            // Nothing bad could happen (I think), so catch it and ignore it    
            try
            {
                os.close();
            }
                
            catch (IOException ioe)
            {
                    
            } 
        }  
    };
    
    
    /**
     * Get the content-type of the requested file
     * 
     * @param fileName requested file
     * @return the MIME string
     */
    private static String contentType(String fileName) 
    {
        if (fileName.endsWith(".htm") || fileName.endsWith(".html") || fileName.endsWith(".txt")) 
        {
            return "text/html";
        } 
        
        else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) 
        {
            return "image/jpeg";
        }
        
        else if (fileName.endsWith(".gif")) 
        {
            return "image/gif";
        } 
        
        else 
        {
            return "application/octet-stream";
        }
    }
}
